package com.yudean.esb.service.handler.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yudean.esb.common.Type;
import com.yudean.esb.mapper.erp.ComplexQueryMapper;
import com.yudean.esb.plugins.SubMapperResultHanlder;
import com.yudean.esb.plugins.component.SQLAdapter;
import com.yudean.esb.plugins.component.SelfMappers;
import com.yudean.esb.service.handler.UniversalQueryService;
import com.yudean.esb.util.ObjectPooledFactoy;
import com.yudean.esb.util.SqlMapBuilder;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.Collections;
import java.util.List;
import java.util.Map;

@Service
@Scope("prototype")
public class UniversalQueryServiceImpl implements UniversalQueryService {
    private final static Logger LOGGER = LoggerFactory.getLogger(UniversalQueryServiceImpl.class);

    private SelfMappers selfMappers;
    @Resource
    private DataSource dataSource;
    @Override
    public String executeService(String serviceID, Map<String, Object> requestParams) {
        LOGGER.info("UniversalQueryService.executeService():handle msg for {serviceID:{}}", serviceID);
        //使用缓存
        try {
            this.selfMappers = ObjectPooledFactoy.get("com.yudean.esb.service.handler.impl.UniversalQueryServiceImpl#selfMappers-" + serviceID);
            if (this.selfMappers == null) {
                this.selfMappers = new SelfMappers(serviceID);
                ObjectPooledFactoy.put("com.yudean.esb.service.handler.impl.UniversalQueryServiceImpl#selfMappers-" + serviceID, this.selfMappers);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

        String pageNo = String.valueOf(requestParams.get("page"));
        String pageSize = String.valueOf(requestParams.get("pageSize"));
        String token = (String) requestParams.get("token");
        String args = String.valueOf(requestParams.get("arg"));
        String userID = String.valueOf(requestParams.get("userID"));
        try {
            String where = buildQuery(args, userID);
            selfMappers.setWhere(where);
        } catch (Exception e) {
            LOGGER.error("execute():解析查询条件失败！err-{}", e.getMessage());
            return null;
        }

        String sql = SqlMapBuilder.build(selfMappers,Integer.parseInt(pageNo),Integer.parseInt(pageSize));
        TransactionFactory transactionFactory = new JdbcTransactionFactory();

        //运行环境
        Environment environment = new Environment(String.valueOf(requestParams.get("targetEnvironment")), transactionFactory, dataSource);
        Configuration configuration = new Configuration(environment);
        configuration.addMapper(ComplexQueryMapper.class);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        SubMapperResultHanlder resultHanlder = new SubMapperResultHanlder(selfMappers,sqlSession);
        sqlSession.select("com.yudean.esb.mapper.erp.ComplexQueryMapper.querySql",new SQLAdapter(sql),resultHanlder);
        List<Map<String, Object>> list = resultHanlder.getResult();
        sqlSession.close();

        String result = null;
        String msg = null;
        String total = null;
        String data = null;
        if (list == null) {
            result = "0";
            msg = "query return null value";
            pageSize = "";
            total = "";
            data = JSONObject.toJSONString(Collections.emptyList());
        } else {
            result = "1";
            msg = "OK";
            pageSize = list.size() + "";
            total = SqlMapBuilder.getTotalRecord(selfMappers,dataSource) + "";
            data = JSONObject.toJSONString(list);
        }
        return wrapToxml(serviceID, token, result, msg, pageNo, pageSize,
                total, data);
    }

    /**
     * convert the request paramater arg to the query condition
     *
     * @param args request
     * @return sql condition
     * @throws Exception
     */
    public String buildQuery(String args, String userID) throws Exception {
        StringBuilder conditonBuilder = new StringBuilder();
        try {
            //验证权限
            String authCol = selfMappers.getAuthCol();
            if (authCol != null && userID != null) {
                conditonBuilder.append(authCol).append(" ='").append(userID).append("'");
            } else {
                conditonBuilder.append(" 1=1 ");
            }
            JSONArray array = JSONObject.parseArray(args);
            if (array != null && array.size() > 0) {
                for (int idx = 0; idx < array.size(); idx++) {
                    JSONObject condition = array.getJSONObject(idx);
                    // 取值
                    String field = condition.getString("field");
                    //判断是否可以查询
                    if (field == null || "".equals(field.trim()) || !selfMappers.canQuery(field)) continue;
                    String type = condition.getString("type");
                    JSONArray value = condition.getJSONArray("value");
                    //保证长度
                    if (value.size() < 1) continue;
                    String colName = selfMappers.getColNameFromNode(field);
                    String tmpQuery = " AND " + colName;
                    // 判断关系类型
                    Type relation = Type.valueOf(type.trim());
                    String singleQuata = "'";
                    // 构造查询条件
                    if (relation == Type.BT) {

                        if (value.size() < 2) continue;
                        String val0 = selfMappers.convert2DbType(field, value.get(0).toString());
                        String val1 = selfMappers.convert2DbType(field, value.get(1).toString());
                        conditonBuilder.append(tmpQuery).append(" BETWEEN ")
                                .append(val0).append(" AND ").append(val1);

                    } else if (relation == Type.LIKE) {

                        conditonBuilder.append(tmpQuery).append(" LIKE ")
                                .append(singleQuata).append("%")
                                .append(value.get(0)).append("%")
                                .append(singleQuata);

                    } else if (relation == Type.IN) {

                        conditonBuilder.append(tmpQuery).append(" IN (");
                        int i = 0;
                        for (; i < value.size() - 1; i++) {
                            String val = selfMappers.convert2DbType(field, value.get(i).toString());
                            conditonBuilder.append(" ").append(val).append(" , ");
                        }
                        String val = selfMappers.convert2DbType(field, value.get(i).toString());
                        conditonBuilder.append(val);
                        conditonBuilder.append(") ");

                    } else if (relation == Type.EQ) {

                        String val = selfMappers.convert2DbType(field, value.get(0).toString());
                        conditonBuilder.append(tmpQuery).append(" = ").append(val);

                    } else if (relation == Type.GT) {

                        String val = selfMappers.convert2DbType(field, value.get(0).toString());
                        conditonBuilder.append(tmpQuery).append(" > ").append(val);

                    } else if (relation == Type.LT) {

                        String val = selfMappers.convert2DbType(field, value.get(0).toString());
                        conditonBuilder.append(tmpQuery).append(" < ").append(val);

                    }
                }
            }
        } catch (Exception e) {
            throw new Exception(e.getMessage(), e.getCause());
        }
        return conditonBuilder.toString();
    }

    /**
     * 将数据生成xml格式
     *
     * @param serviceID 服务ID
     * @param token     安全码
     * @param page      起始页
     * @param pageSize  每页大小
     * @param total     总记录数
     * @param data      数据
     * @return 返回到客户端的XML
     */
    protected String wrapToxml(String serviceID, String token, String result,
                               String msg, String page, String pageSize, String total, String data) {
        Document document = DocumentHelper.createDocument();
        Element root = document.addElement("service");
        Element serviceElement = root.addElement("serviceID");
        serviceElement.setText(serviceID);

        Element tokenElement = root.addElement("token");
        tokenElement.setText(token);
        Element resultElement = root.addElement("result");
        resultElement.setText(result);
        Element msgElement = root.addElement("msg");
        msgElement.setText(msg);

        Element pageElement = root.addElement("page");
        pageElement.setText(page);

        Element sizeElement = root.addElement("pageSize");
        sizeElement.setText(pageSize);

        Element totalElement = root.addElement("total");
        totalElement.setText(total);

        Element dataElement = root.addElement("data");
        dataElement.setText(data);

        return document.asXML();
    }



}
